package com.imooc.trading_system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.imooc.trading_system.dto.LoginUserDto;
import com.imooc.trading_system.enums.BizCodeEnum;
import com.imooc.trading_system.exception.BizException;
import com.imooc.trading_system.interceptor.LoginInterceptor;
import com.imooc.trading_system.model.UserDO;
import com.imooc.trading_system.mapper.UserMapper;
import com.imooc.trading_system.service.UserService;
import com.imooc.trading_system.service.WalletService;
import com.imooc.trading_system.utils.CommonUtils;
import com.imooc.trading_system.utils.JWTUtils;
import com.imooc.trading_system.utils.JsonData;
import com.imooc.trading_system.vo.user.*;
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import org.apache.commons.codec.digest.Md5Crypt;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Feng zhaoxi
 * @since 2022-04-23
 */
@Service
public class UserServiceImpl implements UserService {
    @Resource
    private UserMapper userMapper;
    @Autowired
    private WalletService walletService;

    @Value("${minio.endpointUrl}")
    public String endpointUrl;

    @Value("${minio.accessKey}")
    public String accessKey;

    @Value("${minio.secretKey}")
    public String secretKey;

    @Value("${minio.bucketName}")
    public String bucketName;

    /**
     * 用户登录
     *
     * @param loginUserReqVO
     * @return
     */
    @Override
    public JsonData login(LoginUserReqVO loginUserReqVO) {
        UserDO user = userMapper.selectOne(new QueryWrapper<UserDO>()
                .eq("user", loginUserReqVO.getUser()));
        //用户不存在，返回提示：用户不存在，请先注册
        if (user == null) {
            return JsonData.buildResult(BizCodeEnum.USER_DOES_NOT_EXIST);
        }
        String cryptPwd = Md5Crypt.md5Crypt(loginUserReqVO.getPassword().getBytes(), user.getSecret());
        if (cryptPwd.equals(user.getPassword())) {
            //登录
            user.setLastLoginTime(new Date());
            userMapper.updateById(user);
            LoginRespVO loginRespVO = new LoginRespVO();
            loginRespVO.setId(user.getId());
            loginRespVO.setUser(user.getUser());
            loginRespVO.setToken(JWTUtils.geneJsonWebToken(user));
            return JsonData.buildSuccess(loginRespVO);
        } else {
            return JsonData.buildResult(BizCodeEnum.ACCOUNT_PWD_ERROR);
        }

    }

    /**
     * 用户注册
     *
     * @param registerReqVO
     * @return
     */
    @Override
    public JsonData register(RegisterReqVO registerReqVO) {
        if (!registerReqVO.getInvitationCode().equals("!@1w2i3l4l5i6a7m8#$")) {
            return JsonData.buildResult(BizCodeEnum.INVITATION_CODE_ERROR);
        }
        UserDO userDO = new UserDO();
        BeanUtils.copyProperties(registerReqVO, userDO);
        userDO.setSecret("$1$" + CommonUtils.getStringNumRandom(8));
        String cryptPwd = Md5Crypt.md5Crypt(registerReqVO.getPassword().getBytes(), userDO.getSecret());
        userDO.setPassword(cryptPwd);
        userDO.setLastLoginTime(new Date());
        if (checkUnique(userDO.getUser())) {
            int rows = userMapper.insert(userDO);
            return JsonData.buildSuccess();
        } else {
            return JsonData.buildResult(BizCodeEnum.ACCOUNT_REPEAT);
        }
    }

    private boolean checkUnique(String username) {
        List<UserDO> list = userMapper.selectList(new QueryWrapper<UserDO>().eq("user", username));
        return list.size() <= 0;
    }

    /**
     * 获取登录用户的信息
     *
     * @return
     */
    @Override
    public JsonData getLoginUserInfo() {
        UserDO user = getLoginUser();
        GetLoginUserInfoRespVO loginUserInfoRespVO = new GetLoginUserInfoRespVO();
        BeanUtils.copyProperties(user, loginUserInfoRespVO);
        return JsonData.buildSuccess(loginUserInfoRespVO);
    }

    /**
     * 修改个人信息(除头像)
     *
     * @return
     */
    @Override
    public JsonData updateLoginUserInfo(UpdateLoginUserInfoReqVO updateLoginUserInfoReqVO) {
        UserDO user = getLoginUser();
        if (user == null) {
            return JsonData.buildResult(BizCodeEnum.NO_CORRESPONDING_USER);
        }
        UpdateWrapper<UserDO> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", user.getId());
        user.setEmail(updateLoginUserInfoReqVO.getEmail());
        user.setPhoneNumber(updateLoginUserInfoReqVO.getPhoneNumber());
        user.setUniversity(updateLoginUserInfoReqVO.getUniversity());
        user.setGender(updateLoginUserInfoReqVO.getGender());
        int rows = userMapper.update(user, updateWrapper);
        if (rows == 1) {
            return JsonData.buildSuccess();
        } else {
            return JsonData.buildResult(BizCodeEnum.EDIT_USER_FAILED);
        }
    }

    /**
     * 获取登录用户实例
     *
     * @return
     */
    @Override
    public UserDO getLoginUser() {
        LoginUserDto loginUser = LoginInterceptor.threadLocal.get();
        UserDO user = userMapper.selectOne(new QueryWrapper<UserDO>().eq("id", loginUser.getId()));
        if (user == null) {
            throw new BizException(BizCodeEnum.NO_CORRESPONDING_USER);
        }
        return user;
    }

    /**
     * 上传头像
     *
     * @param file
     * @return
     */
    @Override
    public JsonData uploadHeadImg(MultipartFile file) {
        UserDO user = getLoginUser();
        try {
            // 使用MinIO服务的URL，端口，Access key和Secret key创建一个MinioClient对象
            MinioClient minioClient = MinioClient.builder()
                    .endpoint(endpointUrl)
                    .credentials(accessKey, secretKey)
                    .build();

            // 检查存储桶是否已经存在
            boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
            if (isExist) {
                System.out.println("Bucket already exists.");
            } else {
                // 创建一个名为asiatrip的存储桶，用于存储照片的zip文件。
                minioClient.makeBucket(MakeBucketArgs.builder()
                        .bucket(bucketName)
                        .build());
            }

            // 文件名字
            String fileName = "user_avatar" + "/" + user.getId() + "/head_img";
            // 上传文件 已经文件大小
            // file.getContentType() 文件类型
            minioClient.putObject(
                    PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(
                                    file.getInputStream(), file.getSize(), -1)
                            .contentType(file.getContentType())
                            .build());

            // 返回文件访问路径
            String url = endpointUrl + "/" + bucketName + "/" + fileName;
            UpdateWrapper<UserDO> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", user.getId());
            user.setHeadImg(url);
            int rows = userMapper.update(user, updateWrapper);
            if (rows == 1) {
                return JsonData.buildSuccess(url);
            } else {
                return JsonData.buildResult(BizCodeEnum.UPLOAD_HEAD_IMG_FAILED);
            }
        } catch (Exception e) {
            return JsonData.buildError("失败");
        }
    }

    /**
     * 获取产品发布者的信息
     *
     * @param publishUserId
     * @return
     */
    @Override
    public UserDO getPublishUserInfo(int publishUserId) {
        return userMapper.selectOne(new QueryWrapper<UserDO>()
                .eq("id", publishUserId));
    }

    /**
     * 获取当前日期
     *
     * @return
     */
    @Override
    public JsonData getDate() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String specifiedDay = sdf.format(date);
        GetDateRespVO getDateRespVO = new GetDateRespVO();
        getDateRespVO.setDate(specifiedDay.substring(0, 7));
        getDateRespVO.setDay(specifiedDay.substring(8, 10));
        SimpleDateFormat dateWeek = new SimpleDateFormat("EEEE");
        getDateRespVO.setWeek(dateWeek.format(date));
        return JsonData.buildSuccess(getDateRespVO);
    }
}
